<!DOCTYPE HTML>
<html lang="en-US" >
    
    <head>
        
        <meta charset="UTF-8">
        <title>有限状态机(FSM) | AKKA 2.3.6 Scala 文档</title>
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="generator" content="GitBook 1.0.3">
        <meta name="HandheldFriendly" content="true"/>
        <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black">
        <link rel="apple-touch-icon-precomposed" sizes="152x152" href="../gitbook/images/apple-touch-icon-precomposed-152.png">
        <link rel="shortcut icon" href="../gitbook/images/favicon.ico" type="image/x-icon">
        
    
    
    
    <link rel="next" href="../chapter3/08_persistence.html" />
    
    
    <link rel="prev" href="../chapter3/06_routing.html" />
    

        
    </head>
    <body>
        
        
<link rel="stylesheet" href="../gitbook/style.css">


        
    <div class="book"  data-level="3.7" data-basepath=".." data-revision="1442802141200">
    

<div class="book-summary">
    <div class="book-search">
        <input type="text" placeholder="Type to search" class="form-control" />
    </div>
    <ul class="summary">
        
    	
    	
    	

        

        
    
        
        <li class="chapter " data-level="0" data-path="index.html">
            
                
                    <a href="../index.html">
                        <i class="fa fa-check"></i>
                        
                         Introduction
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="1" data-path="chapter1/introduction.html">
            
                
                    <a href="../chapter1/introduction.html">
                        <i class="fa fa-check"></i>
                        
                            <b>1.</b>
                        
                         引言
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="1.1" data-path="chapter1/01_what_is_akka.html">
            
                
                    <a href="../chapter1/01_what_is_akka.html">
                        <i class="fa fa-check"></i>
                        
                            <b>1.1.</b>
                        
                         Akka是什么?
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="1.2" data-path="chapter1/02_why_akka.html">
            
                
                    <a href="../chapter1/02_why_akka.html">
                        <i class="fa fa-check"></i>
                        
                            <b>1.2.</b>
                        
                         为什么使用Akka?
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="1.3" data-path="chapter1/03_getting_started.html">
            
                
                    <a href="../chapter1/03_getting_started.html">
                        <i class="fa fa-check"></i>
                        
                            <b>1.3.</b>
                        
                         入门
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="1.4" data-path="chapter1/04_the_obligatory_hello_world.html">
            
                
                    <a href="../chapter1/04_the_obligatory_hello_world.html">
                        <i class="fa fa-check"></i>
                        
                            <b>1.4.</b>
                        
                         必修的“Hello World”
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="1.5" data-path="chapter1/05_usecase_and_deployment_scenarios.html">
            
                
                    <a href="../chapter1/05_usecase_and_deployment_scenarios.html">
                        <i class="fa fa-check"></i>
                        
                            <b>1.5.</b>
                        
                         用例和部署场景
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="1.6" data-path="chapter1/06_examples_of_usecases_for_akka.html">
            
                
                    <a href="../chapter1/06_examples_of_usecases_for_akka.html">
                        <i class="fa fa-check"></i>
                        
                            <b>1.6.</b>
                        
                         Akka使用实例
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="2" data-path="chapter2/general.html">
            
                
                    <a href="../chapter2/general.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.</b>
                        
                         概述
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="2.1" data-path="chapter2/01_terminology_concepts.html">
            
                
                    <a href="../chapter2/01_terminology_concepts.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.1.</b>
                        
                         术语，概念
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="2.2" data-path="chapter2/02_actor_systems.html">
            
                
                    <a href="../chapter2/02_actor_systems.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.2.</b>
                        
                         Actor系统
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="2.3" data-path="chapter2/03_what_is_an_actor.html">
            
                
                    <a href="../chapter2/03_what_is_an_actor.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.3.</b>
                        
                         什么是Actor?
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="2.4" data-path="chapter2/04_supervision_and_monitoring.html">
            
                
                    <a href="../chapter2/04_supervision_and_monitoring.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.4.</b>
                        
                         监管与监控
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="2.5" data-path="chapter2/05_actor_references_paths_and_addresses.html">
            
                
                    <a href="../chapter2/05_actor_references_paths_and_addresses.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.5.</b>
                        
                         Actor引用, 路径与地址
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="2.6" data-path="chapter2/06_location_transparency.html">
            
                
                    <a href="../chapter2/06_location_transparency.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.6.</b>
                        
                         位置透明性
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="2.7" data-path="chapter2/07_akka_and_the_java_memory_model.html">
            
                
                    <a href="../chapter2/07_akka_and_the_java_memory_model.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.7.</b>
                        
                         Akka与Java内存模型
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="2.8" data-path="chapter2/08_message_delivery_reliability.html">
            
                
                    <a href="../chapter2/08_message_delivery_reliability.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.8.</b>
                        
                         消息发送语义
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="2.9" data-path="chapter2/09_configuration.html">
            
                
                    <a href="../chapter2/09_configuration.html">
                        <i class="fa fa-check"></i>
                        
                            <b>2.9.</b>
                        
                         配置
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="3" data-path="chapter3/actors.html">
            
                
                    <a href="../chapter3/actors.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.</b>
                        
                         Actors
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="3.1" data-path="chapter3/01_actors.html">
            
                
                    <a href="../chapter3/01_actors.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.1.</b>
                        
                         Actors
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="3.2" data-path="chapter3/02_typed_actors.html">
            
                
                    <a href="../chapter3/02_typed_actors.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.2.</b>
                        
                         有类型Actor
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="3.3" data-path="chapter3/03_fault_tolerance.html">
            
                
                    <a href="../chapter3/03_fault_tolerance.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.3.</b>
                        
                         容错
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="3.3.1" data-path="chapter3/03-1_fault_tolerance_sample.html">
            
                
                    <a href="../chapter3/03-1_fault_tolerance_sample.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.3.1.</b>
                        
                         容错示例
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="3.4" data-path="chapter3/04_dispatchers.html">
            
                
                    <a href="../chapter3/04_dispatchers.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.4.</b>
                        
                         调度器
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="3.5" data-path="chapter3/05_mailboxes.html">
            
                
                    <a href="../chapter3/05_mailboxes.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.5.</b>
                        
                         邮箱
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="3.6" data-path="chapter3/06_routing.html">
            
                
                    <a href="../chapter3/06_routing.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.6.</b>
                        
                         路由
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter active" data-level="3.7" data-path="chapter3/07_fsm.html">
            
                
                    <a href="../chapter3/07_fsm.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.7.</b>
                        
                         有限状态机(FSM)
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="3.8" data-path="chapter3/08_persistence.html">
            
                
                    <a href="../chapter3/08_persistence.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.8.</b>
                        
                         持久化
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="3.9" data-path="chapter3/09_testing_actor_systems.html">
            
                
                    <a href="../chapter3/09_testing_actor_systems.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.9.</b>
                        
                         测试Actor系统
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="3.9.1" data-path="chapter3/09_1_testkit-example.html">
            
                
                    <a href="../chapter3/09_1_testkit-example.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.9.1.</b>
                        
                         TestKit实例
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="3.10" data-path="chapter3/10_actor_dsl.html">
            
                
                    <a href="../chapter3/10_actor_dsl.html">
                        <i class="fa fa-check"></i>
                        
                            <b>3.10.</b>
                        
                         Actor DSL
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="4" data-path="chapter4/futures_and_agents.html">
            
                
                    <a href="../chapter4/futures_and_agents.html">
                        <i class="fa fa-check"></i>
                        
                            <b>4.</b>
                        
                         Futures与Agents
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="4.1" data-path="chapter4/01_futures.html">
            
                
                    <a href="../chapter4/01_futures.html">
                        <i class="fa fa-check"></i>
                        
                            <b>4.1.</b>
                        
                         Futures
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="4.2" data-path="chapter4/02_agents.html">
            
                
                    <a href="../chapter4/02_agents.html">
                        <i class="fa fa-check"></i>
                        
                            <b>4.2.</b>
                        
                         Agents
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="5" data-path="chapter5/networking.html">
            
                
                    <a href="../chapter5/networking.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.</b>
                        
                         网络
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="5.1" data-path="chapter5/01_cluster_cpecification.html">
            
                
                    <a href="../chapter5/01_cluster_cpecification.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.1.</b>
                        
                         集群规格
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="5.2" data-path="chapter5/02_cluster_usage.html">
            
                
                    <a href="../chapter5/02_cluster_usage.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.2.</b>
                        
                         集群用法
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="5.3" data-path="chapter5/03_remoting.html">
            
                
                    <a href="../chapter5/03_remoting.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.3.</b>
                        
                         远程
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="5.4" data-path="chapter5/04_serialization.html">
            
                
                    <a href="../chapter5/04_serialization.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.4.</b>
                        
                         序列化
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="5.5" data-path="chapter5/05_io.html">
            
                
                    <a href="../chapter5/05_io.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.5.</b>
                        
                         I/O
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="5.6" data-path="chapter5/06_using_tcp.html">
            
                
                    <a href="../chapter5/06_using_tcp.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.6.</b>
                        
                         使用TCP
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="5.7" data-path="chapter5/07_using_udp.html">
            
                
                    <a href="../chapter5/07_using_udp.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.7.</b>
                        
                         使用UDP
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="5.8" data-path="chapter5/08_zeromq.html">
            
                
                    <a href="../chapter5/08_zeromq.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.8.</b>
                        
                         ZeroMQ
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="5.9" data-path="chapter5/09_camel.html">
            
                
                    <a href="../chapter5/09_camel.html">
                        <i class="fa fa-check"></i>
                        
                            <b>5.9.</b>
                        
                         Camel
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="6" data-path="chapter6/utilities.html">
            
                
                    <a href="../chapter6/utilities.html">
                        <i class="fa fa-check"></i>
                        
                            <b>6.</b>
                        
                         实用工具
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="6.1" data-path="chapter6/01_event_bus.html">
            
                
                    <a href="../chapter6/01_event_bus.html">
                        <i class="fa fa-check"></i>
                        
                            <b>6.1.</b>
                        
                         事件总线
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="6.2" data-path="chapter6/02_logging.html">
            
                
                    <a href="../chapter6/02_logging.html">
                        <i class="fa fa-check"></i>
                        
                            <b>6.2.</b>
                        
                         日志
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="6.3" data-path="chapter6/03_scheduler.html">
            
                
                    <a href="../chapter6/03_scheduler.html">
                        <i class="fa fa-check"></i>
                        
                            <b>6.3.</b>
                        
                         调度器
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="6.4" data-path="chapter6/04_duration.html">
            
                
                    <a href="../chapter6/04_duration.html">
                        <i class="fa fa-check"></i>
                        
                            <b>6.4.</b>
                        
                         Duration
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="6.5" data-path="chapter6/05_circuit_breaker.html">
            
                
                    <a href="../chapter6/05_circuit_breaker.html">
                        <i class="fa fa-check"></i>
                        
                            <b>6.5.</b>
                        
                         线路断路器
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="6.6" data-path="chapter6/06_akka_extensions.html">
            
                
                    <a href="../chapter6/06_akka_extensions.html">
                        <i class="fa fa-check"></i>
                        
                            <b>6.6.</b>
                        
                         Akka扩展
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="6.7" data-path="chapter6/07_microkernel.html">
            
                
                    <a href="../chapter6/07_microkernel.html">
                        <i class="fa fa-check"></i>
                        
                            <b>6.7.</b>
                        
                         微内核
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="7" data-path="chapter7/howto_common_patterns.html">
            
                
                    <a href="../chapter7/howto_common_patterns.html">
                        <i class="fa fa-check"></i>
                        
                            <b>7.</b>
                        
                         如何使用：常用模式
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="8" data-path="chapter8/experimental_modules.html">
            
                
                    <a href="../chapter8/experimental_modules.html">
                        <i class="fa fa-check"></i>
                        
                            <b>8.</b>
                        
                         实验模块
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="8.1" data-path="chapter3/08_persistence.html">
            
                
                    <a href="../chapter3/08_persistence.html">
                        <i class="fa fa-check"></i>
                        
                            <b>8.1.</b>
                        
                         持久化
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="8.2" data-path="chapter8/02_multi_node_testing.html">
            
                
                    <a href="../chapter8/02_multi_node_testing.html">
                        <i class="fa fa-check"></i>
                        
                            <b>8.2.</b>
                        
                         多节点测试
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="8.3" data-path="chapter8/03_actors.html">
            
                
                    <a href="../chapter8/03_actors.html">
                        <i class="fa fa-check"></i>
                        
                            <b>8.3.</b>
                        
                         Actors(使用Java的Lambda支持)
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="8.4" data-path="chapter8/04_fsm.html">
            
                
                    <a href="../chapter8/04_fsm.html">
                        <i class="fa fa-check"></i>
                        
                            <b>8.4.</b>
                        
                         FSM(使用Java的Lambda支持)
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="8.5" data-path="chapter8/05_external_contributions.html">
            
                
                    <a href="../chapter8/05_external_contributions.html">
                        <i class="fa fa-check"></i>
                        
                            <b>8.5.</b>
                        
                         外部贡献
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="9" data-path="chapter9/information_for_akka_developers.html">
            
                
                    <a href="../chapter9/information_for_akka_developers.html">
                        <i class="fa fa-check"></i>
                        
                            <b>9.</b>
                        
                         Akka开发者信息
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="9.1" data-path="chapter9/01_building_akka.html">
            
                
                    <a href="../chapter9/01_building_akka.html">
                        <i class="fa fa-check"></i>
                        
                            <b>9.1.</b>
                        
                         构建Akka
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="9.2" data-path="chapter9/02_multi_jvm_testing.html">
            
                
                    <a href="../chapter9/02_multi_jvm_testing.html">
                        <i class="fa fa-check"></i>
                        
                            <b>9.2.</b>
                        
                         多JVM测试
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="9.3" data-path="chapter9/03_io_layer_design.html">
            
                
                    <a href="../chapter9/03_io_layer_design.html">
                        <i class="fa fa-check"></i>
                        
                            <b>9.3.</b>
                        
                         I/O层设计
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="9.4" data-path="chapter9/04_developer_guidelines.html">
            
                
                    <a href="../chapter9/04_developer_guidelines.html">
                        <i class="fa fa-check"></i>
                        
                            <b>9.4.</b>
                        
                         开发指南
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="9.5" data-path="chapter9/05_documentation_guidelines.html">
            
                
                    <a href="../chapter9/05_documentation_guidelines.html">
                        <i class="fa fa-check"></i>
                        
                            <b>9.5.</b>
                        
                         文档指南
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="9.6" data-path="chapter9/06_team.html">
            
                
                    <a href="../chapter9/06_team.html">
                        <i class="fa fa-check"></i>
                        
                            <b>9.6.</b>
                        
                         团队
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="10" data-path="chapter10/project_information.html">
            
                
                    <a href="../chapter10/project_information.html">
                        <i class="fa fa-check"></i>
                        
                            <b>10.</b>
                        
                         工程信息
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="10.1" data-path="chapter10/01_migration_guides.html">
            
                
                    <a href="../chapter10/01_migration_guides.html">
                        <i class="fa fa-check"></i>
                        
                            <b>10.1.</b>
                        
                         迁移指南
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="10.2" data-path="chapter10/02_issue_tracking.html">
            
                
                    <a href="../chapter10/02_issue_tracking.html">
                        <i class="fa fa-check"></i>
                        
                            <b>10.2.</b>
                        
                         问题追踪
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="10.3" data-path="chapter10/03_licenses.html">
            
                
                    <a href="../chapter10/03_licenses.html">
                        <i class="fa fa-check"></i>
                        
                            <b>10.3.</b>
                        
                         许可证
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="10.4" data-path="chapter10/04_sponsors.html">
            
                
                    <a href="../chapter10/04_sponsors.html">
                        <i class="fa fa-check"></i>
                        
                            <b>10.4.</b>
                        
                         赞助商
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="10.5" data-path="chapter10/05_project.html">
            
                
                    <a href="../chapter10/05_project.html">
                        <i class="fa fa-check"></i>
                        
                            <b>10.5.</b>
                        
                         项目
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    
        
        <li class="chapter " data-level="11" data-path="chapter11/additional_information.html">
            
                
                    <a href="../chapter11/additional_information.html">
                        <i class="fa fa-check"></i>
                        
                            <b>11.</b>
                        
                         附加信息
                    </a>
                
            
            
            <ul class="articles">
                
    
        
        <li class="chapter " data-level="11.1" data-path="chapter11/01_faq.html">
            
                
                    <a href="../chapter11/01_faq.html">
                        <i class="fa fa-check"></i>
                        
                            <b>11.1.</b>
                        
                         常见问题
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="11.2" data-path="chapter11/02_books.html">
            
                
                    <a href="../chapter11/02_books.html">
                        <i class="fa fa-check"></i>
                        
                            <b>11.2.</b>
                        
                         图书
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="11.3" data-path="chapter11/03_other_language_bindings.html">
            
                
                    <a href="../chapter11/03_other_language_bindings.html">
                        <i class="fa fa-check"></i>
                        
                            <b>11.3.</b>
                        
                         其他语言绑定
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="11.4" data-path="chapter11/04_akka_in_osgi.html">
            
                
                    <a href="../chapter11/04_akka_in_osgi.html">
                        <i class="fa fa-check"></i>
                        
                            <b>11.4.</b>
                        
                         Akka与OSGi
                    </a>
                
            
            
        </li>
    
        
        <li class="chapter " data-level="11.5" data-path="chapter11/05_incomplete_list_of_http_frameworks.html">
            
                
                    <a href="../chapter11/05_incomplete_list_of_http_frameworks.html">
                        <i class="fa fa-check"></i>
                        
                            <b>11.5.</b>
                        
                         部分HTTP框架名单
                    </a>
                
            
            
        </li>
    

            </ul>
            
        </li>
    


        
        <li class="divider"></li>
        <li>
            <a href="http://www.gitbook.io/" target="blank" class="gitbook-link">Published using GitBook</a>
        </li>
        
    </ul>
</div>

    <div class="book-body">
        <div class="body-inner">
            <div class="book-header">
    <!-- Actions Left -->
    <a href="#" class="btn pull-left toggle-summary" aria-label="Toggle summary"><i class="fa fa-align-justify"></i></a>
    <a href="#" class="btn pull-left toggle-search" aria-label="Toggle search"><i class="fa fa-search"></i></a>
    
    <div id="font-settings-wrapper" class="dropdown pull-left">
        <a href="#" class="btn toggle-dropdown" aria-label="Toggle font settings"><i class="fa fa-font"></i>
        </a>
        <div class="dropdown-menu font-settings">
    <div class="dropdown-caret">
        <span class="caret-outer"></span>
        <span class="caret-inner"></span>
    </div>

    <div class="buttons">
        <button type="button" id="reduce-font-size" class="button size-2">A</button>
        <button type="button" id="enlarge-font-size" class="button size-2">A</button>
    </div>

    <div class="buttons font-family-list">
        <button type="button" data-font="0" class="button">Serif</button>
        <button type="button" data-font="1" class="button">Sans</button>
    </div>

    <div class="buttons color-theme-list">
        <button type="button" id="color-theme-preview-0" class="button size-3" data-theme="0">White</button>
        <button type="button" id="color-theme-preview-1" class="button size-3" data-theme="1">Sepia</button>
        <button type="button" id="color-theme-preview-2" class="button size-3" data-theme="2">Night</button>
    </div>
</div>

    </div>

    <!-- Actions Right -->
    
    <div class="dropdown pull-right">
        <a href="#" class="btn toggle-dropdown" aria-label="Toggle share dropdown"><i class="fa fa-share-alt"></i>
        </a>
        <div class="dropdown-menu font-settings dropdown-left">
            <div class="dropdown-caret">
                <span class="caret-outer"></span>
                <span class="caret-inner"></span>
            </div>
            <div class="buttons">
                <button type="button" data-sharing="twitter" class="button">Twitter</button>
                <button type="button" data-sharing="google-plus" class="button">Google</button>
                <button type="button" data-sharing="facebook" class="button">Facebook</button>
                <button type="button" data-sharing="weibo" class="button">Weibo</button>
                <button type="button" data-sharing="instapaper" class="button">Instapaper</button>
            </div>
        </div>
    </div>
    

    
    <a href="#" target="_blank" class="btn pull-right google-plus-sharing-link sharing-link" data-sharing="google-plus" aria-label="Share on Google Plus"><i class="fa fa-google-plus"></i></a>
    
    
    <a href="#" target="_blank" class="btn pull-right facebook-sharing-link sharing-link" data-sharing="facebook" aria-label="Share on Facebook"><i class="fa fa-facebook"></i></a>
    
    
    <a href="#" target="_blank" class="btn pull-right twitter-sharing-link sharing-link" data-sharing="twitter" aria-label="Share on Twitter"><i class="fa fa-twitter"></i></a>
    
    

    <!-- Title -->
    <h1>
        <i class="fa fa-circle-o-notch fa-spin"></i>
        <a href="../" >AKKA 2.3.6 Scala 文档</a>
    </h1>
</div>

            <div class="page-wrapper" tabindex="-1">
                <div class="page-inner">
                
                
                    <section class="normal" id="section-gitbook_86">
                    
                        <h1 id="fsm">有限状态机(FSM)</h1>
<h3 id="">概述</h3>
<p>FSM (有限状态机) 可以mixin到akka Actor中，其概念在<a href="http://www.erlang.org/documentation/doc-4.8.2/doc/design_principles/fsm.html" target="_blank">Erlang 设计原则</a>中有最好的描述。</p>
<p>一个 FSM 可以描述成一组具有如下形式的关系 :</p>
<p>  <strong>State(S) x Event(E) -&gt; Actions (A), State(S&#39;)</strong></p>
<p>这些关系的意思可以这样理解：</p>
<blockquote>
<p>如果我们当前处于状态S，发生了E事件，则我们应执行操作A，然后将状态转换为S’。</p>
</blockquote>
<h3 id="">一个简单的例子</h3>
<p>为了演示<code>FSM</code> trait的大部分功能，考虑一个actor，它接收到一组突然爆发的消息而将其送入邮箱队列，然后在消息爆发期过后或收到flush请求时再对消息进行发送。</p>
<p>首先，假设以下所有代码都使用这些import语句：</p>
<pre><code class="lang-scala"><span class="hljs-keyword">import</span> akka.actor.{ <span class="hljs-type">Actor</span>, <span class="hljs-type">ActorRef</span>, <span class="hljs-type">FSM</span> }
<span class="hljs-keyword">import</span> scala.concurrent.duration._
</code></pre>
<p>我们的 “Buncher” actor的契约是接收或产生以下消息：</p>
<pre><code class="lang-scala"><span class="hljs-comment">// received events</span>
<span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SetTarget</span>(</span>ref: <span class="hljs-type">ActorRef</span>)
<span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Queue</span>(</span>obj: <span class="hljs-type">Any</span>)
<span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">Flush</span>
</span>
<span class="hljs-comment">// sent events</span>
<span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Batch</span>(</span>obj: immutable.<span class="hljs-type">Seq</span>[<span class="hljs-type">Any</span>])
</code></pre>
<p><code>SetTarget</code>用来启动，为<code>Batches</code>设置发送目标；<code>Queue</code>会添加到内部队列而<code>Flush</code>标志着消息爆发的结束。</p>
<pre><code class="lang-scala"><span class="hljs-comment">// states</span>
<span class="hljs-keyword">sealed</span> <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">State</span>
</span><span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">Idle</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">State</span>
</span><span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">Active</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">State</span>
</span>
<span class="hljs-keyword">sealed</span> <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Data</span>
</span><span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">Uninitialized</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Data</span>
</span><span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Todo</span>(</span>target: <span class="hljs-type">ActorRef</span>, queue: immutable.<span class="hljs-type">Seq</span>[<span class="hljs-type">Any</span>]) <span class="hljs-keyword">extends</span> <span class="hljs-type">Data</span>
</code></pre>
<p>这个actor可以处于两种状态: 队列中没有消息（即<code>Idle</code>）或有消息（即<code>Active</code>）。只要一直有消息进来并且没有flush请求，它就停留在active状态。这个actor的内部状态数据是由批消息的发送目标actor引用和实际的消息队列组成.</p>
<p>现在让我们看看我们的FSM actor的框架:</p>
<pre><code class="lang-scala"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Buncher</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Actor</span> <span class="hljs-keyword"><span class="hljs-keyword">with</span></span> <span class="hljs-title">FSM</span>[</span><span class="hljs-type">State</span>, <span class="hljs-type">Data</span>] {

  startWith(<span class="hljs-type">Idle</span>, <span class="hljs-type">Uninitialized</span>)

  when(<span class="hljs-type">Idle</span>) {
    <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(<span class="hljs-type">SetTarget</span>(ref), <span class="hljs-type">Uninitialized</span>) =&gt;
      stay using <span class="hljs-type">Todo</span>(ref, <span class="hljs-type">Vector</span>.empty)
  }

  <span class="hljs-comment">// transition elided ...</span>

  when(<span class="hljs-type">Active</span>, stateTimeout = <span class="hljs-number">1</span> second) {
    <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(<span class="hljs-type">Flush</span> | <span class="hljs-type">StateTimeout</span>, t: <span class="hljs-type">Todo</span>) =&gt;
      goto(<span class="hljs-type">Idle</span>) using t.copy(queue = <span class="hljs-type">Vector</span>.empty)
  }

  <span class="hljs-comment">// unhandled elided ...</span>

  initialize()
}
</code></pre>
<p>基本策略就是声明actor类，混入<code>FSM</code> trait，并将可能的状态和数据设定为类型参数。在actor的内部使用一个DSL来声明状态机：</p>
<ul>
<li><code>startsWith</code>定义初始状态和初始数据</li>
<li>然后对每一个状态有一个<code>when(&lt;state&gt;) { ... }</code>声明待处理的事件（可以是多个，传入的<code>PartialFunction</code>将用<code>orElse</code>进行连接）</li>
<li>最后使用<code>initialize</code>来启动它，这会执行到初始状态的转换并启动定时器（如果需要的话）。</li>
</ul>
<p>在这个例子中，我们从<code>Idle</code>和<code>Uninitialized</code>状态开始，这两种状态下只处理<code>SetTarget()</code>消息；<code>stay</code>准备结束这个事件的处理而不离开当前状态，而<code>using</code>使得FSM将其内部状态（这时为<code>Uninitialized</code>）替换为一个新的包含目标actor引用的<code>Todo()</code>对象。<code>Active</code>状态声明了一个状态超时，意思是如果1秒内没有收到消息，将生成一个<code>FSM.StateTimeout</code>消息。在本例中这与收到<code>Flush</code>指令消息具有相同的效果，即转回<code>Idle</code>状态并将内部队列重置为空vector。但消息是如何进入队列的？由于在两种状态下都要做这件事，我们利用了任何<code>when()</code>块未处理的消息被发送到<code>whenUnhandled()</code>块这个事实：</p>
<pre><code class="lang-scala">whenUnhandled {
  <span class="hljs-comment">// common code for both states</span>
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(<span class="hljs-type">Queue</span>(obj), t @ <span class="hljs-type">Todo</span>(_, v)) =&gt;
    goto(<span class="hljs-type">Active</span>) using t.copy(queue = v :+ obj)

  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(e, s) =&gt;
    log.warning(<span class="hljs-string">"received unhandled request {} in state {}/{}"</span>, e, stateName, s)
    stay
}
</code></pre>
<p>这里第一个case是将<code>Queue()</code>请求加入内部队列中并进入<code>Active</code>状态（当然显然地，如果已经在<code>Active</code>状态则停留），前提是收到<code>Queue()</code>时FSM数据不是<code>Uninitialized</code>。否则——及其它所有未命中的情况——第二个case记录一个警告到日志并保持内部状态。</p>
<p>最后剩下的只有<code>Batches</code>实际上是如何发送到目标的，这里我们使用<code>onTransition</code>机制：你可以声明多个这样的块，在状态切换发生时（即只有当状态真正改变时）所有的块都将被尝试来作匹配。</p>
<pre><code class="lang-scala">onTransition {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Active</span> -&gt; <span class="hljs-type">Idle</span> =&gt;
    stateData <span class="hljs-keyword">match</span> {
      <span class="hljs-keyword">case</span> <span class="hljs-type">Todo</span>(ref, queue) =&gt; ref ! <span class="hljs-type">Batch</span>(queue)
    }
}
</code></pre>
<p>状态转换回调是一个偏函数，它以一对状态作为输入的——当前状态和下一个状态。FSM trait为此提供了一个方便的箭头形式的提取器，非常贴心地提醒你所匹配到的状态转换的方向。在状态转换过程中，如示例所示旧状态数据可以通过<code>stateData</code>获得，新状态数据可以通过<code>nextStateData</code>获得。</p>
<p>要确认这个buncher真实可用，可以很简单地利用<a href="09_testing_actor_systems.html">测试Actor系统(Scala)</a>中的工具写一个测试，它方便地将ScalaTest trait融入<code>AkkaSpec</code>中：</p>
<pre><code class="lang-scala"><span class="hljs-keyword">import</span> akka.actor.<span class="hljs-type">Props</span>
<span class="hljs-keyword">import</span> scala.collection.immutable

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FSMDocSpec</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">MyFavoriteTestFrameWorkPlusAkkaTestKit</span> {</span>

  <span class="hljs-comment">// fsm code elided ...</span>

  <span class="hljs-string">"simple finite state machine"</span> must {

    <span class="hljs-string">"demonstrate NullFunction"</span> in {
      <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">A</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Actor</span> <span class="hljs-keyword"><span class="hljs-keyword">with</span></span> <span class="hljs-title">FSM</span>[</span><span class="hljs-type">Int</span>, <span class="hljs-type">Null</span>] {
        <span class="hljs-function"><span class="hljs-keyword">val</span> <span class="hljs-title">SomeState</span> =</span> <span class="hljs-number">0</span>
        when(<span class="hljs-type">SomeState</span>)(<span class="hljs-type">FSM</span>.<span class="hljs-type">NullFunction</span>)
      }
    }

    <span class="hljs-string">"batch correctly"</span> in {
      <span class="hljs-function"><span class="hljs-keyword">val</span> <span class="hljs-title">buncher</span> =</span> system.actorOf(<span class="hljs-type">Props</span>(classOf[<span class="hljs-type">Buncher</span>], <span class="hljs-keyword">this</span>))
      buncher ! <span class="hljs-type">SetTarget</span>(testActor)
      buncher ! <span class="hljs-type">Queue</span>(<span class="hljs-number">42</span>)
      buncher ! <span class="hljs-type">Queue</span>(<span class="hljs-number">43</span>)
      expectMsg(<span class="hljs-type">Batch</span>(immutable.<span class="hljs-type">Seq</span>(<span class="hljs-number">42</span>, <span class="hljs-number">43</span>)))
      buncher ! <span class="hljs-type">Queue</span>(<span class="hljs-number">44</span>)
      buncher ! <span class="hljs-type">Flush</span>
      buncher ! <span class="hljs-type">Queue</span>(<span class="hljs-number">45</span>)
      expectMsg(<span class="hljs-type">Batch</span>(immutable.<span class="hljs-type">Seq</span>(<span class="hljs-number">44</span>)))
      expectMsg(<span class="hljs-type">Batch</span>(immutable.<span class="hljs-type">Seq</span>(<span class="hljs-number">45</span>)))
    }

    <span class="hljs-string">"not batch if uninitialized"</span> in {
      <span class="hljs-function"><span class="hljs-keyword">val</span> <span class="hljs-title">buncher</span> =</span> system.actorOf(<span class="hljs-type">Props</span>(classOf[<span class="hljs-type">Buncher</span>], <span class="hljs-keyword">this</span>))
      buncher ! <span class="hljs-type">Queue</span>(<span class="hljs-number">42</span>)
      expectNoMsg
    }
  }
}
</code></pre>
<h3 id="">参考</h3>
<h5 id="fsm-trait--fsm-object">FSM Trait 及 FSM Object</h5>
<p><code>FSM</code> trait只能被混入到<code>Actor</code>子类中。这里选择了 使用self类型的写法而不是继承<code>Actor</code>，这样是为了标明事实上创建的是一个actor。//TODO这里代码有误？</p>
<pre><code class="lang-scala"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Buncher</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Actor</span> <span class="hljs-keyword"><span class="hljs-keyword">with</span></span> <span class="hljs-title">FSM</span>[</span><span class="hljs-type">State</span>, <span class="hljs-type">Data</span>] {

  <span class="hljs-comment">// fsm body ...</span>

  initialize()
}
</code></pre>
<blockquote>
<p>注意</p>
<p>FSM特质定义<code>receive</code>方法处理内部消息，并将其它一切通过FSM逻辑传递（根据当前状态）。当重写<code>receive</code>方法，请牢记例如超时状态处理取决于实际通过FSM逻辑传递的消息。</p>
</blockquote>
<p><code>FSM</code> trait 有两个类型参数 :</p>
<ol>
<li>所有状态名称的父类型，通常是一个sealed trait，状态名称作为case object来继承它</li>
<li>状态数据的类型，由<code>FSM</code>模块自己跟踪。</li>
</ol>
<p><a name="fsm-philosophy"></a></p>
<blockquote>
<p>注意</p>
<p>状态数据与状态名称一起描述了状态机的内部状态；如果你坚持这种模式，不向FSM类中加入可变量成员，你就可以充分享受在一些周知的位置改变所有内部状态的好处.</p>
</blockquote>
<h5 id="">定义状态</h5>
<p>状态的定义是通过一次或多次调用</p>
<pre><code>when(&lt;name&gt;[, stateTimeout = &lt;timeout&gt;])(stateFunction)
</code></pre><p>方法。</p>
<p>给定的名称对象必须与为<code>FSM</code> trait指定的第一个参数类型相匹配。这个对象将被用作一个hash表的键，所以你必须确保它正确地实现了<code>equals</code> <code>hashCode</code>方法；特别是它不能为可变变量。满足这些条件的最简单的就是 case objects。</p>
<p>如果给定了<code>stateTimeout</code>参数，那么所有到这个状态的转换，包括停留，缺省都会收到这个超时。初始化转换时显式指定一个超时可以用来覆盖这个缺省行为，更多信息见<a href="#initiating-transitions">发起状态转换</a>。在操作执行的过程中可以通过使用<code>setStateTimeout(state, duration)</code>方法来修改任何状态的超时时间。这使得运行时配置（例如通过外部消息）成为可能。</p>
<p>参数<code>stateFunction</code>是一个<code>PartialFunction[Event, State]</code>，可以很方便地用偏函数的语法来指定，见下例：</p>
<pre><code class="lang-scala">when(<span class="hljs-type">Idle</span>) {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(<span class="hljs-type">SetTarget</span>(ref), <span class="hljs-type">Uninitialized</span>) =&gt;
    stay using <span class="hljs-type">Todo</span>(ref, <span class="hljs-type">Vector</span>.empty)
}

when(<span class="hljs-type">Active</span>, stateTimeout = <span class="hljs-number">1</span> second) {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(<span class="hljs-type">Flush</span> | <span class="hljs-type">StateTimeout</span>, t: <span class="hljs-type">Todo</span>) =&gt;
    goto(<span class="hljs-type">Idle</span>) using t.copy(queue = <span class="hljs-type">Vector</span>.empty)
}
</code></pre>
<p>该<code>Event(msg: Any, data: D)</code> case类将FSM持有的数据类型参数化，从而可以方便地进行模式匹配。</p>
<blockquote>
<p>警告</p>
<p>它要求你为所有可能的FSM状态定义处理程序，否则尝试切换到未声明的状态时会有失败。</p>
</blockquote>
<p>推荐的实践做法是，将状态声明为对象，继承自一个sealed特质，然后验证是否对每一个状态都有<code>when</code>子句。如果你想要一些状态“不被处理”（详见下文），它仍然需要像这样声明：</p>
<pre><code class="lang-scala">when(<span class="hljs-type">SomeState</span>)(<span class="hljs-type">FSM</span>.<span class="hljs-type">NullFunction</span>)
</code></pre>
<h5 id="">定义初始状态</h5>
<p>每个FSM都需要一个起点，用以下代码声明</p>
<pre><code class="lang-scala">startWith(state, data[, timeout])
</code></pre>
<p>其中可选的超时参数将覆盖所有为期望的初始状态所指定的值。如果你想要取消缺省的超时，使用<code>Duration.Inf</code>。</p>
<h5 id="">未处理事件</h5>
<p>如果一个状态未能处理一个收到的事件，日志中将记录一条警告。这种情况下如果你想做点其它的事，你可以使用<code>whenUnhandled(stateFunction)</code>来指定：</p>
<pre><code class="lang-scala">whenUnhandled {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(x: <span class="hljs-type">X</span>, data) =&gt;
    log.info(<span class="hljs-string">"Received unhandled event: "</span> + x)
    stay
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(msg, _) =&gt;
    log.warning(<span class="hljs-string">"Received unknown event: "</span> + msg)
    goto(<span class="hljs-type">Error</span>)
}
</code></pre>
<p>在此处理程序中可以使用<code>stateName</code>方法查询FSM的状态。</p>
<p><strong>重要</strong>：这个处理器不会入栈叠加，这意味着<code>whenUnhandled</code>的每一次调用都会覆盖先前指定的处理程序。</p>
<h3 id="a-nameinitiating-transitionsa"><a name="initiating-transitions"></a>发起状态转换</h3>
<p>任何<code>stateFunction</code>的结果都必须是下一个状态的定义，除非是终止FSM，这种情况在<a href="#termination-from-inside">从内部终止</a>中介绍。状态定义可以是当前状态，由<code>stay</code>指令描述，或由<code>goto(state)</code>指定的另一个状态。结果对象可以通过下面列出的修饰器作进一步的限制：</p>
<ul>
<li><p><code>forMax(duration)</code></p>
<p>这个修饰器为新状态指定了一个状态超时。这意味着将启动一个定时器，它过期时将向FSM发送一个<code>StateTimeout</code>消息。其间接收到任何其它消息，定时器都将被取消；你可以确定的事实是<code>StateTimeout</code>消息不会在任何一个中间消息之后被处理。</p>
<p>这个修饰器也可以用于覆盖任何对目标状态指定的缺省超时。如果要取消缺省超时，可以使用<code>Duration.Inf</code>。</p>
</li>
<li><p><code>using(data)</code></p>
<p>这个修饰器用给定的新数据替换旧的状态数据。如果你遵循<a href="#fsm-philosophy">上面的建议</a>，这是内部状态数据被修改的唯一位置。</p>
</li>
<li><p><code>replying(msg)</code></p>
<p>这个修饰器为当前处理完的消息发送一个应答，不同的是它不会改变状态转换。</p>
</li>
</ul>
<p>所有的修饰器都可以链式调用来获得优美简洁的表达方式：</p>
<pre><code class="lang-scala">when(<span class="hljs-type">SomeState</span>) {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(msg, _) =&gt;
    goto(<span class="hljs-type">Processing</span>) using (newData) forMax (<span class="hljs-number">5</span> seconds) replying (<span class="hljs-type">WillDo</span>)
}
</code></pre>
<p>事实上这里所有的括号都不是必须的，但它们在视觉上将修饰器和它们的参数区分开，因而使代码对于他人来说有更好的可读性。</p>
<blockquote>
<p>注意</p>
<p>请注意<code>return</code>语句不可以用于<code>when</code>或类似的代码块中；这是Scala的限制。要么使用<code>if () ... else ...</code>重构你的代码，要么将它改写到一个方法定义中。</p>
</blockquote>
<h5 id="">监控状态转换</h5>
<p>在概念上，转换发生在“两个状态之间”，也就是在你放在事件处理代码块执行的任何操作之后；这是显然的，因为只有在事件处理逻辑返回了值以后，才能确定下一个状态。相对于设置内部状态变量，你不需要担心操作顺序的细节，因为FSM actor中的所有代码都是在一个线程中运行的。</p>
<h6 id="">内部监控</h6>
<p>到目前为止，FSM DSL都围绕着状态和事件。另外一种视角是将其描述成一系列的状态转换。是通过这个方法实现的</p>
<pre><code>onTransition(handler)
</code></pre><p>它将操作与状态转换联系起来，而不是联系状态与事件。这个处理器是一个偏函数，它以一对状态作为输入；不需要结果状态，因为不可能改变正在进行的状态转换。</p>
<pre><code class="lang-scala">onTransition {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Idle</span> -&gt; <span class="hljs-type">Active</span> =&gt; setTimer(<span class="hljs-string">"timeout"</span>, <span class="hljs-type">Tick</span>, <span class="hljs-number">1</span> second, <span class="hljs-literal">true</span>)
  <span class="hljs-keyword">case</span> <span class="hljs-type">Active</span> -&gt; _    =&gt; cancelTimer(<span class="hljs-string">"timeout"</span>)
  <span class="hljs-keyword">case</span> x -&gt; <span class="hljs-type">Idle</span>      =&gt; log.info(<span class="hljs-string">"entering Idle from "</span> + x)
}
</code></pre>
<p>提取器<code>-&gt;</code>用来解开状态对，并以清晰的形式表达了状态转换的方向。与通常的模式匹配一样，可以用<code>_</code>来表示不关心的内容；或者你可以将不关心的状态绑定到一个无约束的变量，例如像上一个例子那样供记日志使用。</p>
<p>也可以向<code>onTransition</code>传递一个以两个状态为参数的函数，此时你的状态转换处理逻辑是定义成方法的：</p>
<pre><code class="lang-scala">onTransition(handler _)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">handler</span>(</span>from: <span class="hljs-type">StateType</span>, to: <span class="hljs-type">StateType</span>) {
  <span class="hljs-comment">// handle it here ...</span>
}
</code></pre>
<p>用这个方法注册的处理器是堆栈迭加的，这样你可以将<code>onTransition</code>块和<code>when</code>块分散定义以适应设计的需要。但需要注意的是，<em>所有的处理器对每一次状态转换都会被调用</em>，而不只是最先匹配的那个。这是有意设计的，使得你可以将某一部分状态转换处理放在某一个地方，而不用担心先前的定义会屏蔽后面的逻辑；当然这些操作还是按定义的顺序执行的。</p>
<blockquote>
<p>注意</p>
<p>这种内部监控可以用于通过状态转换来构建你的FSM，这样在添加新的目标状态时，不会忘记例如在离开某个状态时，取消定时器这种操作。</p>
</blockquote>
<h6 id="">外部监控</h6>
<p>可以通过发送一个<code>SubscribeTransitionCallBack(actorRef)</code>消息注册外部actor，来接收状态转换的通知。这个被命名的actor将立即收到<code>CurrentState(self, stateName)</code>消息，并在之后每次进入新状态时收到<code>Transition(actorRef, oldState, newState)</code>消息。可以通过向FSM actor发送<code>UnsubscribeTransitionCallBack(actorRef)</code>来注销外部监控actor。</p>
<p>停止一个监听器，而不注销，将不会从注册列表中移除它；需要在停止监听器前使用<code>UnsubscribeTransitionCallback</code>。</p>
<h5 id="">转换状态</h5>
<p>给<code>when()</code>传递的偏函数参数，可以使用Scala充分的函数式编程工具来转换。为了保留类型推断，还有一个辅助函数，它可以在通用处理逻辑中使用，并被应用到不同子句：</p>
<pre><code class="lang-scala">when(<span class="hljs-type">SomeState</span>)(transform {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(bytes: <span class="hljs-type">ByteString</span>, read) =&gt; stay using (read + bytes.length)
} using {
  <span class="hljs-keyword">case</span> s @ <span class="hljs-type">FSM</span>.<span class="hljs-type">State</span>(state, read, timeout, stopReason, replies) <span class="hljs-keyword">if</span> read &gt; <span class="hljs-number">1000</span> =&gt;
    goto(<span class="hljs-type">Processing</span>)
})
</code></pre>
<p>不用说此方法的参数也可能被存储，被多次使用，例如在几个不同的<code>when()</code>代码块中应用相同的转换：</p>
<pre><code class="lang-scala"><span class="hljs-function"><span class="hljs-keyword">val</span> <span class="hljs-title">processingTrigger</span>:</span> <span class="hljs-type">PartialFunction</span>[<span class="hljs-type">State</span>, <span class="hljs-type">State</span>] = {
  <span class="hljs-keyword">case</span> s @ <span class="hljs-type">FSM</span>.<span class="hljs-type">State</span>(state, read, timeout, stopReason, replies) <span class="hljs-keyword">if</span> read &gt; <span class="hljs-number">1000</span> =&gt;
    goto(<span class="hljs-type">Processing</span>)
}

when(<span class="hljs-type">SomeState</span>)(transform {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(bytes: <span class="hljs-type">ByteString</span>, read) =&gt; stay using (read + bytes.length)
} using processingTrigger)
</code></pre>
<h5 id="">定时器</h5>
<p>除了状态超时，FSM还管理以<code>String</code>类型名称为标识的定时器。你可以用下面代码设置定时器</p>
<pre><code>setTimer(name, msg, interval, repeat)
</code></pre><p>其中<code>msg</code>是经过<code>interval</code>时间以后发送的消息对象。 如果<code>repeat</code>设成<code>true</code>，定时器将以<code>interval</code>参数指定的时间段重复规划。添加新的计时器之前，具有相同名称的任何现有计时器将被自动取消。</p>
<p>可以用下面代码取消定时器</p>
<pre><code>cancelTimer(name)
</code></pre><p>取消操作确保立即执行，这意味着在这个调用之后，定时器已经规划的消息将不会执行，即使定时器已经发起并入队该消息。任何定时器的状态可以用下面的代码进行查询</p>
<pre><code>isTimerActive(name)
</code></pre><p>这些具名定时器是对状态超时的补充，因为它们不受中间收到的其它消息的影响。</p>
<h5 id="a-nametermination-from-insidea"><a name="termination-from-inside"></a>从内部终止</h5>
<p>可以像下面这样指定结果状态来终止FSM</p>
<pre><code>stop([reason[, data]])
</code></pre><p>其中的<code>reason</code>必须是<code>Normal</code>（默认值）、<code>Shutdown</code>或<code>Failure(reason)</code>之一，可以提供第二个参数来改变状态数据，在终止处理器中可以使用该数据。</p>
<blockquote>
<p>注意</p>
<p>必须注意<code>stop</code>并不会中止当前的操作并立即停止FSM。<code>stop</code>操作必须像状态转换一样从事件处理器中返回（但要注意<code>return</code>语句不能用在<code>when</code>代码块中）。</p>
</blockquote>
<pre><code class="lang-scala">when(<span class="hljs-type">Error</span>) {
  <span class="hljs-keyword">case</span> <span class="hljs-type">Event</span>(<span class="hljs-string">"stop"</span>, _) =&gt;
    <span class="hljs-comment">// do cleanup ...</span>
    stop()
}
</code></pre>
<p>你可以用<code>onTermination(handler)</code>来指定当FSM停止时要运行的代码。其中的handler是以一个<code>StopEvent(reason, stateName, stateData)</code>为参数的偏函数：</p>
<pre><code class="lang-scala">onTermination {
  <span class="hljs-keyword">case</span> <span class="hljs-type">StopEvent</span>(<span class="hljs-type">FSM</span>.<span class="hljs-type">Normal</span>, state, data)         =&gt; <span class="hljs-comment">// ...</span>
  <span class="hljs-keyword">case</span> <span class="hljs-type">StopEvent</span>(<span class="hljs-type">FSM</span>.<span class="hljs-type">Shutdown</span>, state, data)       =&gt; <span class="hljs-comment">// ...</span>
  <span class="hljs-keyword">case</span> <span class="hljs-type">StopEvent</span>(<span class="hljs-type">FSM</span>.<span class="hljs-type">Failure</span>(cause), state, data) =&gt; <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>对于使用<code>whenUnhandled</code>的场合，这个处理器不会堆栈迭加，所以每次<code>onTermination</code>调用都会替换先前指定的处理器。</p>
<h5 id="">从外部终止</h5>
<p>当与FSM关联的<code>ActorRef</code>被<code>stop</code>方法停止后，它的<code>postStop</code> hook 将被执行。在<code>FSM</code>特质中的缺省实现是执行<code>onTermination</code>处理器（如果有的话）来处理<code>StopEvent(Shutdown, ...)</code>事件。</p>
<blockquote>
<p>警告</p>
<p>如果你重写<code>postStop</code>并而希望你的<code>onTermination</code>处理器被调用，不要忘记调用<code>super.postStop</code>。</p>
</blockquote>
<h3 id="">测试和调试有限状态机</h3>
<p>在开发和调试过程中，FSM和其它actor一样需要照顾。<a href="09_testing_actor_systems.html#testfsmref">测试有限状态机</a>以及下文中介绍了一些专门的工具。</p>
<h5 id="">事件跟踪</h5>
<p><a href="../chapter2/09_configuration.html">配置文件</a>中的<code>akka.actor.debug.fsm</code>打开用<code>LoggingFSM</code>实例完成的事件跟踪日志：</p>
<pre><code class="lang-scala"><span class="hljs-keyword">import</span> akka.actor.<span class="hljs-type">LoggingFSM</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFSM</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Actor</span> <span class="hljs-keyword"><span class="hljs-keyword">with</span></span> <span class="hljs-title">LoggingFSM</span>[</span><span class="hljs-type">StateType</span>, <span class="hljs-type">Data</span>] {
  <span class="hljs-comment">// body elided ...</span>
}
</code></pre>
<p>这个FSM将以DEBUG级别记录日志：</p>
<ul>
<li>所有处理完的事件，包括<code>StateTimeout</code>和计划的定时器消息</li>
<li>所有具名定时器的设置和取消</li>
<li>所有的状态转换</li>
</ul>
<p>生命周期变化及特殊消息可以如<a href="09_testing_actor_systems.html#actor-logging-scala">Actor</a>中所述进行日志记录。</p>
<h5 id="">滚动事件日志</h5>
<p><code>LoggingFSM</code>特质为FSM添加了一个新的特性：一个滚动的事件日志，它可以在debugging中使用（跟踪为什么FSM会进入某个失败的状态）或其它的新用法：</p>
<pre><code class="lang-scala"><span class="hljs-keyword">import</span> akka.actor.<span class="hljs-type">LoggingFSM</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyFSM</span> <span class="hljs-keyword"><span class="hljs-keyword">extends</span></span> <span class="hljs-title">Actor</span> <span class="hljs-keyword"><span class="hljs-keyword">with</span></span> <span class="hljs-title">LoggingFSM</span>[</span><span class="hljs-type">StateType</span>, <span class="hljs-type">Data</span>] {
  <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">logDepth</span> =</span> <span class="hljs-number">12</span>
  onTermination {
    <span class="hljs-keyword">case</span> <span class="hljs-type">StopEvent</span>(<span class="hljs-type">FSM</span>.<span class="hljs-type">Failure</span>(_), state, data) =&gt;
      <span class="hljs-function"><span class="hljs-keyword">val</span> <span class="hljs-title">lastEvents</span> =</span> getLog.mkString(<span class="hljs-string">"\n\t"</span>)
      log.warning(<span class="hljs-string">"Failure in state "</span> + state + <span class="hljs-string">" with data "</span> + data + <span class="hljs-string">"\n"</span> +
        <span class="hljs-string">"Events leading up to this point:\n\t"</span> + lastEvents)
  }
  <span class="hljs-comment">// ...</span>
}
</code></pre>
<p><code>logDepth</code>缺省值为0，意思是关闭事件日志。</p>
<blockquote>
<p>警告</p>
<p>日志缓冲区是在actor创建时分配的，这也是为什么logDepth的配置使用了虚方法调用。如果你想用一个<code>val</code>对其进行覆盖，必须保证它的初始化在<code>LoggingFSM</code>的初始化之前完成，而且在缓冲区分配完成后不要修改<code>logDepth</code>返回的值。</p>
</blockquote>
<p>事件日志的内容可以用<code>getLog</code>方法获取，它返回一个<code>IndexedSeq[LogEntry]</code>，其中最老的条目下标为0。</p>
<h3 id="">示例</h3>
<p>在<a href="http://www.typesafe.com/platform/getstarted" target="_blank">Typesafe Activator</a>的模板工程<a href="http://www.typesafe.com/activator/template/akka-sample-fsm-scala" target="_blank">Akka FSM in Scala</a>中，可以找到一个比Actor’s <code>become/unbecome</code>更大的FSM示例。</p>

                    
                    </section>
                
                
                </div>
            </div>
        </div>

        
        <a href="../chapter3/06_routing.html" class="navigation navigation-prev " aria-label="Previous page: 路由"><i class="fa fa-angle-left"></i></a>
        
        
        <a href="../chapter3/08_persistence.html" class="navigation navigation-next " aria-label="Next page: 持久化"><i class="fa fa-angle-right"></i></a>
        
    </div>
</div>

        
<script src="../gitbook/app.js"></script>

    
    <script src="https://cdn.mathjax.org/mathjax/2.4-latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    

    
    <script src="../gitbook/plugins/gitbook-plugin-mathjax/plugin.js"></script>
    

<script>
require(["gitbook"], function(gitbook) {
    var config = {"fontSettings":{"theme":null,"family":"sans","size":2}};
    gitbook.start(config);
});
</script>

        
    </body>
    
</html>
